package com.yhy.wxzn.wcs.device.plc.siemens;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.yhy.wxzn.common.enums.HoistStatus;
import com.yhy.wxzn.common.enums.WcsDeviceTypeEnums;

import com.yhy.wxzn.common.enums.WcsTaskTypeEnums;
import com.yhy.wxzn.common.exception.WmsBusinessException;
import com.yhy.wxzn.common.utils.ListHelper;
import com.yhy.wxzn.common.utils.SpringUtil;
import com.yhy.wxzn.wcs.device.plc.bean.BasePlc;
import com.yhy.wxzn.wcs.entity.WcsElevatorTask;
import com.yhy.wxzn.wcs.device.plc.bean.HoistPlc;
import com.yhy.wxzn.wcs.device.plc.bean.TransmissionPlc;
import com.yhy.wxzn.wcs.enums.TaskStatus;
import com.yhy.wxzn.wcs.service.IWcsDeviceLogService;
import com.yhy.wxzn.wcs.service.IWcsElevatorTaskService;
import com.yhy.wxzn.wcs.utils.PlcUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Auther: 97354
 * @Date: 2023/11/6 16:16
 * @Description: SiemensHoistProtocol
 * @Version 1.0.0
 */
//@Component
@Slf4j
public class SiemensHoistProtocol extends Thread{

    private Integer deviceCode;
    private String plcNo;
    public volatile SiemensPlcDriver siemensPlcDriver;
    private IWcsElevatorTaskService elevatorTaskService;
    private IWcsDeviceLogService deviceLogService;

    public Integer getDeviceCode() {
        return deviceCode;
    }

    public void setDeviceCode(Integer deviceCode) {
        this.deviceCode = deviceCode;
    }

    public String getPlcNo() {
        return plcNo;
    }

    public void setPlcNo(String plcNo) {
        this.plcNo = plcNo;
    }

    private void init() {
        elevatorTaskService = SpringUtil.getBean(IWcsElevatorTaskService.class);
        deviceLogService = SpringUtil.getBean(IWcsDeviceLogService.class);
    }

    @Override
    public void run() {
        //等待Spring 容器加载完成
        while (true) {
            try {
                if (SpringUtil.getApplicationContext() != null) {
                    init();
                    break;
                }
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        while (true) {
            try {
                if (!siemensPlcDriver.siemensHelper.isConnectd()) {
                    sleep(10000);
                    continue;
                }
                hoistProcess();
                crossLayerProcess();
                sleep(100);
            } catch (Exception e) {
                log.error("提升机任务处理异常", e);
            }
        }
    }

    private void crossLayerProcess() {
//        try {
//            if (!CollectionUtils.isEmpty(siemensPlcDriver.getHoistDataPacket().getHoistReadPlcMap())) {
//                List<McsCrossLayerTask> mcsCrossLayerTaskList = mcsCrossLayerTaskService.getUnfinishedList(deviceInfo.getDeviceCode());
//                if (CollectionUtils.isEmpty(mcsCrossLayerTaskList)) {
//                    return;
//                }
//                HoistPlc hoistPlc = siemensPlcDriver.getHoistDataPacket().getHoistReadPlcMap().get(deviceInfo.getDeviceCode());
//                if (null == hoistPlc) {
//                    return;
//                }
//                synchronized (deviceInfo.getDeviceCode().intern()) {
//                    //任务完成
////                    finishCrossTask(mcsCrossLayerTaskList, hoistPlc);
//                    //任务下发
////                    sendCrossTask(mcsCrossLayerTaskList, hoistPlc);
//                }
//            }
//        } catch (Exception ex) {
//            log.error("crossLayerProcess 异常", ex);
//        }
    }

//    private void finishCrossTask(List<McsCrossLayerTask> mcsCrossLayerTaskList, HoistPlc hPlc) {
//        //检查是否有跨层任务已开始
//        McsCrossLayerTask mcsCrossLayerTask = ListHelper.firstOrDefault(mcsCrossLayerTaskList, t -> CrossStatus.START.getTaskProgress() == t.getStatus());
//        if (null == mcsCrossLayerTask) {
//            return;
//        }
//        String taskJsonLog = JSON.toJSONString(mcsCrossLayerTask);
//        try {
//            //信号检查
//            crossTaskCheck(hPlc, mcsCrossLayerTask, CrossStatus.START.getTaskProgress());
//            //任务处理
//            mcsCrossLayerReportService.insertCrossLayerReport(mcsCrossLayerTask, WorkType.FINISH_TASK.getTaskProgress());
//            mcsCrossLayerTask.setStatus(CrossStatus.FINISH.getTaskProgress());
//            mcsCrossLayerTask.setFinishTime(new Date());
//            mcsCrossLayerTask.setRemark("");
//            mcsCrossLayerTaskService.updateById(mcsCrossLayerTask);
//            log.info("{}提升机跨层阶段任务完成，更新跨层任务状态为2，任务信息：{}", hPlc.getHoistId(), taskJsonLog);
//            //任务日志
//            String desc = CrossType.ofValue(mcsCrossLayerTask.getTaskType()) != null ? CrossType.ofValue(mcsCrossLayerTask.getTaskType()).getDesc() : "未知";
//            String msg = hPlc.getHoistId() + " 跨层：" + desc + "任务完成，" + "提升机当前层=" + hPlc.getFloor() + "，准出入小车=" + hPlc.getAccessCar();
//            mcsTaskLogService.insertMcsTaskLog(
//                    mcsCrossLayerTask.getTaskId(),
//                    null,
//                    hPlc.getHoistId(),
//                    msg,
//                    desc);
//        } catch (WcsException e) {
//            //log.warn("{}有待完成的跨层任务，{}，任务信息：{}", getHoistId(), e.getMessage(), taskJsonLog);
//            overTask(mcsCrossLayerTask, mcsCrossLayerTask.getStartTime(), e.getMessage());
//        }
//    }

    private void hoistProcess() {
//        try {
//            if (!CollectionUtils.isEmpty(siemensPlcDriver.hoistDataPacket.getHoistReadPlcMap())) {
//                List<WcsElevatorTask> mcsTaskInfoList = elevatorTaskService.getUnfinishedByHoistList(plcNo);
//                if (CollectionUtils.isEmpty(mcsTaskInfoList)) {
//                    return;
//                }
//                HoistPlc hoistPlc = siemensPlcDriver.hoistDataPacket.getHoistReadPlcMap().get(deviceCode);
//                if (null == hoistPlc) {
//                    return;
//                }
//                synchronized (deviceCode.intern()) {
//                    //任务开始
//                    startHoistTask(mcsTaskInfoList, hoistPlc);
//                    //任务结束
//                    finishHoistTask(mcsTaskInfoList, hoistPlc);
//                    //任务下发
//                    sendHoistTask(mcsTaskInfoList, hoistPlc);
//                }
//            }
//        } catch (Exception ex) {
//            log.error("hoistProcess 异常", ex);
//        }
    }

    private void sendHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        //检查是否有eis任务需要下发
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) && TaskStatus.READY.getTaskProgress() == t.getTaskStatus()
        );
        //无任务
        if (null == mcsTaskInfo) {
            return;
        }
        String taskJsonLog = JSON.toJSONString(mcsTaskInfo);
        try {
            //信号检查
            hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getSource(), TaskStatus.READY.getTaskProgress());
            //写PLC指令
            mcsWritePlc(mcsTaskInfo);
            //try {
            //    mcsWriteTransmissionPlc(mcsTaskInfo);
            //} catch (Exception e) {
            //    log.info("{}提升机任务下发链条机失败，失败原因：{}，任务信息：{}", hPlc.getHoistId(), e.getMessage(), taskJsonLog);
            //}
            //锁提升机
//            WcsDeviceInfo mcsHoist = siemensPlcDriver.plcDataPacket.getDevicePlcMap().get(hPlc.getHoistId());
//            mcsHoist.setLocking(1);
//            deviceInfoService.updateById(mcsHoist);
            hPlc.setLocking(1);
            log.info("{}提升机锁定，更新任务状态为1，任务信息：{}", hPlc.getHoistId(), taskJsonLog);
            //改任务状态为已下发
            mcsTaskInfo.setTaskStatus(TaskStatus.SEND.getTaskProgress());
            mcsTaskInfo.setSendTime(new Date());
            mcsTaskInfo.setRemark("");
            elevatorTaskService.updateById(mcsTaskInfo);
            //任务日志
            String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务下发PLC成功, 提升机 " + hPlc.getHoistId() + mcsTaskInfo.getSource() + ">>" + mcsTaskInfo.getTarget();
//            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务下发PLC成功, 提升机 " + hPlc.getHoistId() + " 锁定状态=" + mcsHoist.getLocking() + "，" + mcsTaskInfo.getSource() + ">>" + mcsTaskInfo.getTarget();
            String content = "【"+desc+"】"+msg;
            deviceLogService.genCoordLog(hPlc.getHoistId(),content);
        } catch (WmsBusinessException e) {
            //log.warn("{}有待发送任务，{}，任务信息：{}", getHoistId(), e.getMessage(), taskJsonLog);
            overTask(mcsTaskInfo,e.getMessage());
        }
    }

    private void mcsWritePlc(WcsElevatorTask mcsTaskInfo) {
        WcsTaskTypeEnums taskType = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType());
        switch (Objects.requireNonNull(taskType)) {
            case INBOUND_H:
            case OUTBOUND_H:
                mcsWriteHoistPlc(mcsTaskInfo);
                break;
            default:
                log.error(String.format("任务类型%s不存在", mcsTaskInfo.getTaskType()));
                throw new WmsBusinessException("未知的任务类型");
        }
    }

    private void mcsWriteHoistPlc(WcsElevatorTask mcsTaskInfo) {
        BasePlc sourcePlc = getPlcPropertyByCoordAndType(mcsTaskInfo.getSource(),WcsDeviceTypeEnums.ELV.getCode());
        if (null == sourcePlc) {
            throw new WmsBusinessException(String.format("%s PLC读值地址不存在，请检查配置", mcsTaskInfo.getSource()));
        }
        BasePlc targetPlc = getPlcPropertyByCoordAndType(mcsTaskInfo.getTarget(),WcsDeviceTypeEnums.ELV.getCode());
        if (null == targetPlc) {
            throw new WmsBusinessException(String.format("%s PLC读值地址不存在，请检查配置", mcsTaskInfo.getTarget()));
        }
        int sourceFloor = Integer.parseInt(mcsTaskInfo.getSource().substring(0, 2));
        int sourceDevice = sourcePlc.getStation();
        int targetFloor = Integer.parseInt(mcsTaskInfo.getTarget().substring(0, 2));
        int targetDevice = targetPlc.getStation();
        int type;

        WcsTaskTypeEnums taskType = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType());
        switch (Objects.requireNonNull(taskType)) {
            case INBOUND_H:
                type = 1;
                break;
            case OUTBOUND_H:
                type = 2;
                break;
            default:
                type = 0;
        }
        boolean result = writeHoistPlcAddress(
                mcsTaskInfo.getTaskNo(),
                sourcePlc.getWriteAddress(),
                sourceFloor,
                sourceDevice,
                targetFloor,
                targetDevice,
                type,
                0
                //mcsTaskInfo.getSerialNo()
        );
        if (!result) {
            throw new WmsBusinessException("PLC写入失败，请查看PLC日志");
        }
    }

    private BasePlc getPlcPropertyByCoordAndType(String coordInput,String typeInput) {
        if(WcsDeviceTypeEnums.TSL.getCode().equals(typeInput)){
            //获取输送线点位
            if (!CollectionUtils.isEmpty(siemensPlcDriver.driverData.getTransLinePlcMap())) {
                return siemensPlcDriver.driverData.getTransLinePlcMap().get(coordInput);
            }
        }else if(WcsDeviceTypeEnums.ELV.getCode().equals(typeInput)){
            //获取提升机点位
            if (!CollectionUtils.isEmpty(siemensPlcDriver.driverData.getCoordPlcMap())) {
                return siemensPlcDriver.driverData.getCoordPlcMap().get(coordInput);
            }
        }
        return null;
    }

    private boolean writeHoistPlcAddress(String taskNo, String address, int sourceFloor, int sourceDevice, int targetFloor, int targetDevice, int type, int mcsId) {
        //todo 改。。。。。。。。。。。。。。。。。
        //byte[] bytes = PlcUtils.taskHoistByte(sourceFloor, sourceDevice, targetFloor, targetDevice, type, mcsId);
//        Map<String, Object> map = Maps.newHashMap();
//        map.put("起始层", sourceFloor);
//        map.put("起始工位", sourceDevice);
//        map.put("目标层", targetFloor);
//        map.put("目标工位", targetDevice);
//        map.put("任务类型", type);
//        map.put("任务号", mcsId);
//        map.put("Wms任务号", taskNo);
//        return siemensPlcDriver.savePlcLog(address, bytes, map);
        return true;
    }

    private void finishHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        //检查任务结束
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) &&
                        ArrayUtils.contains(new int[]{TaskStatus.SEND.getTaskProgress(), TaskStatus.START.getTaskProgress()}, t.getTaskStatus()));
        if (null == mcsTaskInfo) {
            return;
        }
        String taskJsonLog = JSON.toJSONString(mcsTaskInfo);
        try {
            //信号检查
            hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getTarget(), TaskStatus.START.getTaskProgress());
            //GCS点位清除
//            gcsClearTask(hPlc, mcsTaskInfo);
            //任务回告
//            finishTaskReport(mcsTaskInfo);
            //提升机解锁
//            WcsDeviceInfo mcsHoist = siemensPlcDriver.plcDataPacket.getDevicePlcMap().get(hPlc.getHoistId());
////            mcsHoist.setLocking(0);
//            deviceInfoService.updateById(mcsHoist);
            hPlc.setLocking(1);
            log.info("{}提升机解锁，提升机任务完成，任务信息：{}", hPlc.getHoistId(), taskJsonLog);
            //修改任务状态为完成
            mcsTaskInfo.setTaskStatus(TaskStatus.FINISH.getTaskProgress());
            mcsTaskInfo.setFinishTime(new Date());
            mcsTaskInfo.setRemark("");
            elevatorTaskService.updateById(mcsTaskInfo);
            log.info("{}任务回告完成，更新任务状态为3，任务信息：{}", mcsTaskInfo.getTaskNo(), taskJsonLog);
            //任务日志
            String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
//            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务完成，提升机 " + hPlc.getHoistId() + " 当前层=" + hPlc.getFloor() + "，锁定状态=" + mcsHoist.getLocking();
            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务完成，提升机 " + hPlc.getHoistId() + " 当前层=" + hPlc.getFloor();
            String content = "【"+desc+"】"+msg;
            deviceLogService.genCoordLog(hPlc.getHoistId(),content);
        } catch (WmsBusinessException e) {
            //log.warn("{}有已开始的任务，{}，任务信息：{}", getHoistId(), e.getMessage(), taskJsonLog);
            overTask(mcsTaskInfo,e.getMessage());
        }
    }

    private void startHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        //检查任务开始
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) && TaskStatus.SEND.getTaskProgress() == t.getTaskStatus()
        );
        if (null == mcsTaskInfo) {
            return;
        }
        String taskJsonLog = JSON.toJSONString(mcsTaskInfo);
        try {
            //信号检查
            hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getSource(), TaskStatus.SEND.getTaskProgress());
            //GCS点位清除
//            gcsClearTask(hPlc, mcsTaskInfo);
            //任务回告
//            startTaskReport(mcsTaskInfo);
            //修改任务状态为开始
            mcsTaskInfo.setTaskStatus(TaskStatus.START.getTaskProgress());
            mcsTaskInfo.setStartTime(new Date());
            mcsTaskInfo.setRemark("");
            elevatorTaskService.updateById(mcsTaskInfo);
            log.info("{}任务回告开始，更新任务状态为2，任务信息：{}", mcsTaskInfo.getTaskNo(), taskJsonLog);
            //任务日志
            String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务开始，提升机 " + hPlc.getHoistId() + " 当前层=" + hPlc.getFloor();
            String content = "【"+desc+"】"+msg;
            deviceLogService.genCoordLog(hPlc.getHoistId(),content);
        } catch (WmsBusinessException e) {
            overTask(mcsTaskInfo,e.getMessage());
        }
    }

    private void overTask(WcsElevatorTask mcsTaskInfo,String msg) {
        if (msg.equals(mcsTaskInfo.getRemark())) {
            return;
        }
        mcsTaskInfo.setRemark(msg);
        elevatorTaskService.updateById(mcsTaskInfo);
    }

    private void hoistTaskCheck(HoistPlc hPlc, WcsElevatorTask mcsTaskInfo, String coord, int status) {
        //int mcsId = mcsTaskInfo.getSerialNo();
        //提升机信号检查
        if (null == hPlc) {
            throw new WmsBusinessException(String.format("%s 未初始化，请检查配置", hPlc.getHoistId()));
        }
        if (!hPlc.isAuto()) {
            throw new WmsBusinessException(String.format("%s 不是自动状态，等待系统切换为自动状态", hPlc.getHoistId()));
        }
        if (HoistStatus.Auto.getValue() != hPlc.getAutoStatus()) {
            throw new WmsBusinessException(String.format("%s 不是联机自动状态，等待设备切换为联机自动状态", hPlc.getHoistId()));
        }
        //输送线信号检查
        TransmissionPlc tPlc = (TransmissionPlc)getPlcPropertyByCoordAndType(coord,WcsDeviceTypeEnums.TSL.getCode());
        if (null == tPlc) {
            throw new WmsBusinessException(String.format("%s 未初始化，请检查配置", coord));
        }
        if (!tPlc.isAuto()) {
            throw new WmsBusinessException(String.format("%s 不是自动状态，等待系统切换为自动状态", tPlc.getStation()));
        }
        if (tPlc.getStatus() != 2) {
            throw new WmsBusinessException(String.format("%s 不是联机自动状态，等待设备切换为联机自动状态", tPlc.getStation()));
        }
        if (TaskStatus.SEND.getTaskProgress() == status) {
            //任务开始检查
            if (tPlc.getInPlaceNum() == 1) {
                throw new WmsBusinessException(String.format("%s 有载位信号，等待容器进提升机", tPlc.getStation()));
            }
//            if (tPlc.getDeviceNum() == mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号未清空，等待容器进提升机", tPlc.getStation()));
//            }
//            if (hPlc.getHaveStock() == 0) {
//                throw new WmsBusinessException(String.format("%s 轿厢无货，请检查容器/光电是否正常", hPlc.getHoistId()));
//            }
//            if (hPlc.getHaveCar() == 1) {
//                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
//            }
//            if (hPlc.getTaskId() != mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号%s与MCS任务号%s不一致，等待容器进入轿厢", hPlc.getHoistId(), hPlc.getTaskId(), mcsId));
//            }
        } else if (TaskStatus.START.getTaskProgress() == status) {
            //任务完成检查
            if (tPlc.getInPlaceNum() == 0) {
                throw new WmsBusinessException(String.format("%s 无载位信号，等待容器送达", tPlc.getStation()));
            }
//            if (tPlc.getDeviceNum() != mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号%s与MCS任务号%s不一致，等待容器送达", tPlc.getStation(), tPlc.getDeviceNum(), mcsId));
//            }
//            if (hPlc.getHaveStock() == 1) {
//                throw new WmsBusinessException(String.format("%s 轿厢有货，请检查容器/光电是否正常", hPlc.getHoistId()));
//            }
//            if (hPlc.getHaveCar() == 1) {
//                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
//            }
        } else if (TaskStatus.READY.getTaskProgress() == status) {
            //任务下发检查
            if (tPlc.getInPlaceNum() == 0) {
                throw new WmsBusinessException(String.format("%s 无载位信号，请检查容器/光电是否正常", tPlc.getStation()));
            }
            if (hPlc.getWorkStatus() != 1) {
                throw new WmsBusinessException(String.format("%s 不是就绪状态，等待设备就绪", hPlc.getHoistId()));
            }
//            if (mcsHoist.getLocking() == 1) {
//                throw new WmsBusinessException(String.format("%s 暂时锁定，等待提升机解锁", hPlc.getHoistId()));
//            }
//            if (hPlc.getHaveStock() == 1) {
//                throw new WmsBusinessException(String.format("%s 轿厢有货，请检查容器/光电是否正常", hPlc.getHoistId()));
//            }
//            if (hPlc.getHaveCar() == 1) {
//                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
//            }
        }
    }
}
